Lumiera 0.pre.04~rc.1
»edit your freedom«
Loading...
Searching...
No Matches
time.cpp
Go to the documentation of this file.
1/*
2 Time - Lumiera time handling foundation
3
4 Copyright (C)
5 2008, Christian Thaeter <ct@pipapo.org>
6 2010, Stefan Kangas <skangas@skangas.se>
7 2011, Hermann Vosseler <Ichthyostega@web.de>
8
9  **Lumiera** is free software; you can redistribute it and/or modify it
10  under the terms of the GNU General Public License as published by the
11  Free Software Foundation; either version 2 of the License, or (at your
12  option) any later version. See the file COPYING for further details.
13
14* *****************************************************************/
15
16
36#include "lib/error.hpp"
37#include "lib/rational.hpp"
39#include "lib/format-string.hpp"
40#include "lib/util-quant.hpp"
41#include "lib/util.hpp"
42
43#include <limits>
44#include <string>
45#include <sstream>
46#include <boost/rational.hpp>
47#include <boost/lexical_cast.hpp>
48
49using std::string;
50using util::limited;
51using util::floordiv;
54using boost::rational_cast;
55using boost::lexical_cast;
56
57#undef MAX
58#undef MIN
59
60
61namespace lib {
62namespace meta {
63 extern const std::string FAILURE_INDICATOR;
64}
65namespace time {
66
67 namespace error = lumiera::error;
68
69 const raw_time_64 TimeValue::SCALE = 1'000'000;
70
71
73 const Time Time::MAX ( TimeValue::buildRaw_(+std::numeric_limits<raw_time_64>::max() / 30) );
75 const Time Time::ZERO;
76
79
80 const Offset Offset::ZERO (Time::ZERO);
81
82
83
84 namespace { // local definitions for the implementation....
85
91
92
93 const FSecs FSEC_MAX{std::numeric_limits<int64_t>::max() / lib::time::TimeValue::SCALE};
94
95 Literal DIAGNOSTIC_FORMAT{"%s%01d:%02d:%02d.%03d"};
96
97
107 build_time_from (FSecs const& fractionalSeconds)
108 {
109 // avoid numeric wrap from values not representable as 64bit µ-ticks
110 if (abs(fractionalSeconds) > lib::time::FSEC_MAX)
111 return (fractionalSeconds < 0? -1:+1)
112 * std::numeric_limits<int64_t>::max();
113
114 return raw_time_64(util::reQuant (fractionalSeconds.numerator()
115 ,fractionalSeconds.denominator()
117 ));
118 }
119
120
122 build_time_from (long millis, uint secs, uint mins, uint hours)
123 {
124 raw_time_64 time = millis
125 + 1000 * secs
126 + 1000 * 60 * mins
127 + 1000 * 60 * 60 * hours;
129 return time;
130 }
131 }//(End)local definitions
132
133
134
145 Time::Time ( long millis
146 , uint secs
147 , uint mins
148 , uint hours
149 )
150 : TimeValue(build_time_from (millis,secs,mins,hours))
151 { }
152
153
158 Time::Time (FSecs const& fractionalSeconds)
159 : TimeValue(build_time_from (fractionalSeconds))
160 { }
161
162 Offset::Offset (FSecs const& delta_in_secs)
163 : TimeValue{buildRaw_(symmetricLimit (build_time_from (delta_in_secs)
164 ,Duration::MAX))}
165 { }
166
167
171 TimeValue::operator string() const
172 {
173 raw_time_64 time = t_;
174 int64_t millis, seconds;
175 bool negative = (time < 0);
176
177 if (negative) time = -time;
178 time /= TIME_SCALE_MS;
179 millis = time % 1000;
180 seconds = time / 1000;
181
182 return string (negative ? "-" : "")
183 + (seconds>0 or time==0? lexical_cast<string> (seconds)+"s" : "")
184 + (millis>0? lexical_cast<string> (millis)+"ms" : "")
185 ;
186 }
187
196 Time::operator string() const
197 {
198 raw_time_64 time = t_;
199 int millis, seconds, minutes, hours;
200 bool negative = (time < 0);
201
202 if (negative)
203 time = -time;
204
205 time /= TIME_SCALE_MS;
206 millis = time % 1000;
207 time /= 1000;
208 seconds = time % 60;
209 time /= 60;
210 minutes = time % 60;
211 time /= 60;
212 hours = time;
213
214 return util::_Fmt{string(DIAGNOSTIC_FORMAT)}
215 % (negative? "-":"")
216 % hours
217 % minutes
218 % seconds
219 % millis;
220 }
221
222
223 Offset::operator string() const
224 {
225 return (t_< 0? "" : "∆")
226 + TimeValue::operator string();
227 }
228
229 Duration::operator string() const
230 {
231 return "≺"+TimeValue::operator string()+"≻";
232 }
233
234 TimeSpan::operator string() const
235 {
236 return string (start())
237 + string (duration());
238 }
239
240
241 namespace {
242 template<typename RAT>
243 string
244 renderFraction (RAT const& frac, Literal postfx) noexcept
245 try {
246 std::ostringstream buffer;
247 if (1 == frac.denominator() or 0 == frac.numerator())
248 buffer << frac.numerator() << postfx;
249 else
250 buffer << frac <<postfx;
251 return buffer.str();
252 }
253 catch(...)
254 { return meta::FAILURE_INDICATOR; }
255 }
256
258 FrameRate::operator string() const
259 {
260 return renderFraction (*this, "FPS");
261 }
262
263
264
267 TimeValue
269 {
270 return reinterpret_cast<TimeValue const&> (raw);
271 }
272
273
274
276 const FrameRate FrameRate::PAL (25);
277 const FrameRate FrameRate::NTSC (30000,1001);
278 const FrameRate FrameRate::STEP (1);
279
280 const FrameRate FrameRate::HALTED (1,std::numeric_limits<int>::max());
281
282
287 {
288 if (HALTED > *this)
289 throw error::Logic ("Impossible to quantise to an zero spaced frame grid"
290 , error::LUMIERA_ERROR_BOTTOM_VALUE);
291
292 return Duration (1, *this);
293 }
294
295
300 const uint RATE_LIMIT{std::numeric_limits<uint>::max() / 1024};
301
308 boost::rational<uint>
310 {
311 const double UPPER_LIMIT = int64_t(RATE_LIMIT*1024) << 31;
312 const int64_t HAZARD = util::ilog2(RATE_LIMIT);
313
314 double doo = limited (1.0, fabs(fps) * RATE_LIMIT + 0.5, UPPER_LIMIT);
315 int64_t boo(doo);
316 util::Rat quantised{boo
317 ,int64_t(RATE_LIMIT)
318 };
319
320 int64_t num = quantised.numerator();
321 int64_t toxic = util::ilog2(abs(num));
322 toxic = util::max (0, toxic - HAZARD);
323
324 int64_t base = quantised.denominator();
325 if (toxic)
326 {
327 base = util::max (base >> toxic, 1);
328 num = util::reQuant (num, quantised.denominator(), base);
329 }
330 return {limited (1u, num, RATE_LIMIT)
331 ,limited (1u, base, RATE_LIMIT)
332 };
333 }
334
339 boost::rational<uint>
340 __framerate_approximation (size_t cnt, Duration timeReference)
341 {
342 boost::rational<uint64_t> quot{cnt, _raw(timeReference)};
343 if (quot.denominator() < RATE_LIMIT
344 and quot.numerator() < RATE_LIMIT*1024/1e6)
345 return {uint(quot.numerator()) * uint(Time::SCALE)
346 ,uint(quot.denominator())
347 };
348 // precise computation can not be handled numerically...
349 return __framerate_approximation (rational_cast<double>(quot) * Time::SCALE);
350 }
351
352
353
354
356 Offset
357 Offset::stretchedByRationalFactor (boost::rational<int64_t> factor) const
358 {
359 boost::rational<int64_t> distance (this->t_);
360 distance *= factor;
361 raw_time_64 microTicks = floordiv (distance.numerator(), distance.denominator());
362 return Offset{buildRaw_(microTicks)};
363 }
364
365
367 Offset
368 Offset::stretchedByFloatFactor (double factor) const
369 {
370 double distance(this->t_);
371 distance *= factor;
372 raw_time_64 microTicks = floor (distance);
373 return Offset{buildRaw_(microTicks)};
374 }
375
376
377 namespace {
379 framecount_to_time (uint64_t frameCount, FrameRate const& fps)
380 {
381 // convert to 64bit
382 boost::rational<uint64_t> framerate (fps.numerator(), fps.denominator());
383
384 return rational_cast<raw_time_64> (lib::time::TimeValue::SCALE * frameCount / framerate);
385 }
386 }
387
390 : TimeValue{buildRaw_(
391 count? (count<0? -1:+1) * framecount_to_time (::abs(count), fps)
392 :_raw(Duration::NIL))}
393 { }
394
395
396
399
401 const Duration Duration::MAX = []{
402 auto maxDelta {Time::MAX - Time::MIN};
403 // bypass limit check, which requires Duration::MAX
404 return reinterpret_cast<Duration const&> (maxDelta);
405 }();
406
407 const TimeSpan TimeSpan::ALL {Time::MIN, Duration::MAX};
408
409}} // namespace lib::Time
410
411
412
413namespace util {
414 string
416 {
417 return lib::time::renderFraction (val, "sec");
418 }
419} // namespace util
420
Inline string literal.
Definition symbol.hpp:78
Duration is the internal Lumiera time metric.
static const Duration MAX
maximum possible temporal extension
static const Duration NIL
constant to indicate "no duration"
Framerate specified as frames per second.
static const FrameRate STEP
1 frame per second
Duration duration() const
duration of one frame
Definition time.cpp:286
static const FrameRate PAL
predefined constant for PAL framerate
static const FrameRate NTSC
static const FrameRate HALTED
Offset measures a distance in time.
Offset stretchedByFloatFactor(double) const
Definition time.cpp:368
Offset(TimeValue const &distance=Time::ZERO)
static const Offset ZERO
Offset stretchedByRationalFactor(boost::rational< int64_t >) const
Definition time.cpp:357
static const TimeSpan ALL
basic constant internal time value.
static const raw_time_64 SCALE
Number of micro ticks (µs) per second as basic time scale.
static TimeValue buildRaw_(raw_time_64)
Definition time.cpp:268
raw_time_64 t_
the raw (internal) time value used to implement the time types
static const Time NEVER
border condition marker value. NEVER >= any time value
static const Time MIN
static const Time ANYTIME
border condition marker value. ANYTIME <= any time value
static const Time ZERO
static const Time MAX
Time(int)
suppress possible direct conversions
A front-end for using printf-style formatting.
Lumiera error handling (C++ interface).
Front-end for printf-style string template interpolation.
unsigned int uint
Definition integral.hpp:29
int64_t raw_time_64
Definition job.h:50
const string FAILURE_INDICATOR
raw_time_64 framecount_to_time(uint64_t frameCount, FrameRate const &fps)
Definition time.cpp:379
raw_time_64 build_time_from(FSecs const &fractionalSeconds)
Converts a fraction of seconds to Lumiera's internal opaque time scale.
Definition time.cpp:107
string renderFraction(RAT const &frac, Literal postfx) noexcept
Definition time.cpp:244
const raw_time_64 TIME_SCALE_MS(lib::time::TimeValue::SCALE/1000)
scale factor used locally within this implementation header.
int64_t FrameCnt
relative framecount or frame number.
Definition digxel.hpp:310
int64_t raw_time_64
Raw µ-tick time representation used in Lumiera.
const uint RATE_LIMIT
a rather arbitrary safety limit imposed on internal numbers used to represent a frame rate.
Definition time.cpp:300
boost::rational< int64_t > FSecs
rational representation of fractional seconds
boost::rational< uint > __framerate_approximation(double fps)
Definition time.cpp:309
Implementation namespace for support and library code.
LumieraError< LERR_(LOGIC)> Logic
Definition error.hpp:207
constexpr int ilog2(I num)
Integral binary logarithm (disregarding fractional part)
auto max(IT &&elms)
boost::rational< int64_t > Rat
Definition rational.hpp:73
I floordiv(I num, I den)
floor function for integer arithmetics.
constexpr NUM limited(NB lowerBound, NUM val, NB upperBound)
force a numeric to be within bounds, inclusively
Definition util.hpp:91
int64_t reQuant(int64_t num, int64_t den, int64_t u)
Re-Quantise a number into a new grid, truncating to the next lower grid point.
Definition rational.hpp:120
Rational number support, based on boost::rational.
static std::string invoke(X const &x) noexcept
a family of time value like entities and their relationships.
Utilities for quantisation (grid alignment) and comparisons.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
#define MAX(A, B)
the inevitable MAX macro, sometimes still necessary in template code
Definition util.hpp:518