Lumiera 0.pre.04~rc.1
»edit your freedom«
Loading...
Searching...
No Matches
timecode.cpp
Go to the documentation of this file.
1/*
2 Timecode - implementation of fixed grid aligned time specifications
3
4 Copyright (C)
5 2010, Hermann Vosseler <Ichthyostega@web.de>
6
7  **Lumiera** is free software; you can redistribute it and/or modify it
8  under the terms of the GNU General Public License as published by the
9  Free Software Foundation; either version 2 of the License, or (at your
10  option) any later version. See the file COPYING for further details.
11
12* *****************************************************************/
13
14
22#include "lib/time/timecode.hpp"
25#include "lib/time/formats.hpp"
26#include "lib/util.hpp"
27#include "lib/util-quant.hpp"
28
29#include <regex>
30#include <functional>
31#include <boost/lexical_cast.hpp>
32
33using util::unConst;
35using util::floorwrap;
36using std::string;
37using std::regex;
38using std::smatch;
39using std::regex_search;
40using boost::lexical_cast;
41
42namespace lumiera {
43namespace error {
44 LUMIERA_ERROR_DEFINE (INVALID_TIMECODE, "timecode format error, illegal value encountered");
45}}
46
47namespace lib {
48namespace time {
49 namespace error = lumiera::error;
50
51 namespace format { /* ================= Timecode implementation details ======== */
52
53
54
63 TimeValue
64 Frames::parse (string const& frameNumber, QuantR frameGrid)
65 {
66 static regex frameNr_parser{"(?:^|[^\\d\\.\\-])(\\-?\\d+)#"}; // no leading [.-\d], digit+'#'
67 smatch match; // note: ECMA regexp does not support lookbehind
68 if (regex_search (frameNumber, match, frameNr_parser))
69 return frameGrid.timeOf (lexical_cast<FrameCnt> (match[1]));
70 else
71 throw error::Invalid ("unable to parse framecount \""+frameNumber+"\""
72 , LERR_(INVALID_TIMECODE));
73 }
74
75
77 Smpte::parse (string const&, QuantR)
78 {
79 UNIMPLEMENTED("parsing SMPTE timecode");
80 }
81
82
84 Hms::parse (string const&, QuantR)
85 {
86 UNIMPLEMENTED("parse a hours:mins:secs time specification");
87 }
88
89
112 Seconds::parse (string const& seconds, QuantR grid)
113 {
114 static regex fracSecs_parser ("(?:^|[^\\./\\d\\-])(\\-?\\d+)(?:([\\-\\+]\\d+)?/(\\d+))?sec");
115 //__no leading[./-\d] number [+-] number '/' number 'sec'
116
117 #define SUB_EXPR(N) lexical_cast<int> (match[N])
118 smatch match;
119 if (regex_search (seconds, match, fracSecs_parser))
120 if (match[2].matched)
121 {
122 // complete spec with all parts
123 FSecs fractionalPart (SUB_EXPR(2), SUB_EXPR(3));
124 int fullSeconds (SUB_EXPR(1));
125 return grid.timeOf (fullSeconds + fractionalPart);
126 }
127 else
128 if (match[3].matched)
129 {
130 // only a fractional part was given
131 return grid.timeOf (FSecs (SUB_EXPR(1), SUB_EXPR(3)));
132 }
133 else
134 {
135 // just simple non-fractional seconds
136 return grid.timeOf (FSecs (SUB_EXPR(1)));
137 }
138 else
139 throw error::Invalid ("unable to parse \""+seconds+"\" as (fractional)seconds"
140 , LERR_(INVALID_TIMECODE));
141 }
142
143
144
145
149 void
150 Frames::rebuild (FrameNr& frameNr, QuantR quantiser, TimeValue const& rawTime)
151 {
152 frameNr.setValueRaw (quantiser.gridPoint (rawTime));
153 }
154
157 Frames::evaluate (FrameNr const& frameNr, QuantR quantiser)
158 {
159 return quantiser.timeOf (frameNr);
160 }
161
162
167 void
168 Smpte::rebuild (SmpteTC& tc, QuantR quantiser, TimeValue const& rawTime)
169 {
170 tc.clear();
171 tc.frames = quantiser.gridPoint (rawTime);
172 // will automatically wrap over to the seconds, minutes and hour fields
173 }
174
178 Smpte::evaluate (SmpteTC const& tc, QuantR quantiser)
179 {
180 uint frameRate = tc.getFps();
181 int64_t gridPoint(tc.frames);
182 gridPoint += int64_t(tc.secs) * frameRate;
183 gridPoint += int64_t(tc.mins) * frameRate * 60;
184 gridPoint += int64_t(tc.hours) * frameRate * 60 * 60;
185 return quantiser.timeOf (tc.sgn * gridPoint);
186 }
187
201 uint
202 Smpte::getFramerate (QuantR quantiser_, TimeValue const& rawTime)
203 {
204 FrameCnt refCnt = quantiser_.gridPoint(rawTime);
205 FrameCnt newCnt = quantiser_.gridPoint(Time(0,1) + rawTime);
206 FrameCnt effectiveFrames = newCnt - refCnt;
207 ENSURE (1000 > effectiveFrames);
208 ENSURE (0 < effectiveFrames);
209 return uint(effectiveFrames);
210 }
211
212
231 void
233 {
234 if (tc.hours < 0)
236 }
237 }
238
239
240 namespace { // Timecode implementation details
241
243
244 void
245 wrapFrames (SmpteTC* thisTC, int rawFrames)
246 {
247 Div scaleRelation = floorwrap<int> (rawFrames, thisTC->getFps());
248 thisTC->frames.setValueRaw (scaleRelation.rem);
249 thisTC->secs += scaleRelation.quot;
250 }
251
252 void
253 wrapSeconds (SmpteTC* thisTC, int rawSecs)
254 {
255 Div scaleRelation = floorwrap (rawSecs, 60);
256 thisTC->secs.setValueRaw (scaleRelation.rem);
257 thisTC->mins += scaleRelation.quot;
258 }
259
260 void
261 wrapMinutes (SmpteTC* thisTC, int rawMins)
262 {
263 Div scaleRelation = floorwrap (rawMins, 60);
264 thisTC->mins.setValueRaw (scaleRelation.rem);
265 thisTC->hours += scaleRelation.quot;
266 }
267
268 void
269 wrapHours (SmpteTC* thisTC, int rawHours)
270 {
271 thisTC->hours.setValueRaw (rawHours);
273 }
274
275
276 using std::bind;
277 using std::placeholders::_1;
278
281 inline void
283 {
284 thisTC.hours.installMutator (wrapHours, thisTC);
285 thisTC.mins.installMutator (wrapMinutes, thisTC);
286 thisTC.secs.installMutator (wrapSeconds, thisTC);
287 thisTC.frames.installMutator(wrapFrames, thisTC);
288 }
289
290 }//(End)implementation details
291
292
294 FrameNr::FrameNr (QuTime const& quantisedTime)
295 : TCode(quantisedTime)
296 , CountVal()
297 {
298 quantisedTime.castInto (*this);
299 }
300
301
303 SmpteTC::SmpteTC (QuTime const& quantisedTime)
304 : TCode(quantisedTime)
305 , effectiveFramerate_(Format::getFramerate (*quantiser_, quantisedTime))
306 {
307 setupComponentNormalisation (*this);
308 quantisedTime.castInto (*this);
309 }
310
311
313 : TCode(o)
314 , effectiveFramerate_(o.effectiveFramerate_)
315 {
316 setupComponentNormalisation (*this);
317 sgn = o.sgn;
318 hours = o.hours;
319 mins = o.mins;
320 secs = o.secs;
321 frames = o.frames;
322 }
323
324
325 SmpteTC&
327 {
328 if (not isSameObject (*this, o))
329 {
330 TCode::operator= (o);
332 sgn = o.sgn;
333 hours = o.hours;
334 mins = o.mins;
335 secs = o.secs;
336 frames = o.frames;
337 }
338 return *this;
339 }
340
341
343 HmsTC::HmsTC (QuTime const& quantisedTime)
344 : TCode(quantisedTime)
345// : tpoint_(quantisedTime) //////////////////////////////////////////////////////////////////////TICKET #736 implement HMS format
346 { }
347
348
350 Secs::Secs (QuTime const& quantisedTime)
351 : TCode(quantisedTime)
352// : sec_(TimeVar(quantisedTime) / TimeValue::SCALE) /////////////////////////////////////////////////////TICKET #736 implement Seconds format
353 { }
354
355
356
357 void
359 {
361 secs.setValueRaw (0);
362 mins.setValueRaw (0);
363 hours.setValueRaw (0);
364 sgn.setValueRaw (+1);
365 }
366
367
368 void
370 {
371 TimeValue point = Format::evaluate (*this, *quantiser_);
372 Format::rebuild (*this, *quantiser_, point);
373 }
374
375
387 void
389 {
390 int fr (getFps());
391 int f (fr - frames); // revert orientation
392 int s (60 - secs); // of the components
393 int m (60 - mins); //
394 int h = -hours; // assumed to be negative
395 sgn *= -1; // flip sign field
396
397 if (f < fr) --s; else f -= fr;
398 if (s < 60) --m; else s -= 60;
399 if (m < 60) --h; else m -= 60;
400
402 mins = m; // invoking setters
403 secs = s; // ensures normalisation
404 frames = f;
405 }
406
407
408 uint
410 {
411 return effectiveFramerate_;
412 }
413
414
415 string
417 {
418 string tc;
419 tc.reserve(15);
420 tc += sgn.show();
421 tc += hours.show();
422 tc += ':';
423 tc += mins.show();
424 tc += ':';
425 tc += secs.show();
426 tc += ':';
427 tc += frames.show();
428 return tc;
429 }
430
431 SmpteTC&
433 {
434 frames += sgn;
435 return *this;
436 }
437
438 SmpteTC&
440 {
441 frames -= sgn;
442 return *this;
443 }
444
445 namespace {
448 }
449
451 int
453 {
454 return (_raw (tpoint_) / TIME_SCALE_sec) % 60;
455 }
456
458 int
460 {
461 return (_raw (tpoint_) / TIME_SCALE_sec / 60) % 60;
462 }
463
465 int
467 {
468 return _raw (tpoint_) / TIME_SCALE_sec / 60 / 60;
469 }
470
472 double
474 {
475 return (_raw (tpoint_) / TIME_SCALE_ms) % 1000;
476 }
477
483}} // lib::time
484
A number element for building structured numeric displays.
Definition digxel.hpp:217
void setValueRaw(NUM newVal)
Definition digxel.hpp:279
digxel::CBuf show() const
Definition digxel.hpp:262
void installMutator(FUN mutate, THIS &self)
install an external functor to be applied on any new digxel value.
Definition digxel.hpp:241
A frame counting timecode value.
Definition timecode.hpp:99
FrameNr(QuTime const &quantisedTime)
Definition timecode.cpp:294
double getMillis() const
Definition timecode.cpp:473
int getMins() const
Definition timecode.cpp:459
int getSecs() const
Definition timecode.cpp:452
HmsTC(QuTime const &quantisedTime)
Definition timecode.cpp:343
int getHours() const
Definition timecode.cpp:466
grid aligned time specification, referring to a specific scale.
Definition timequant.hpp:91
void castInto(TC &timecode) const
quantise into implicit grid, then rebuild the timecode
Secs(QuTime const &quantisedTime)
Definition timecode.cpp:350
Classical Timecode value reminiscent to SMPTE format.
Definition timecode.hpp:147
SmpteTC & operator++()
Definition timecode.cpp:432
virtual string show() const
Definition timecode.cpp:416
void invertOrientation()
flip the orientation of min, sec, and frames.
Definition timecode.cpp:388
SmpteTC & operator--()
Definition timecode.cpp:439
uint getFps() const
Definition timecode.cpp:409
SmpteTC & operator=(SmpteTC const &)
Definition timecode.cpp:326
SmpteTC(QuTime const &quantisedTime)
Definition timecode.cpp:303
Interface: fixed format timecode specification.
Definition timecode.hpp:57
basic constant internal time value.
static const raw_time_64 SCALE
Number of micro ticks (µs) per second as basic time scale.
Lumiera's internal time value datatype.
#define LUMIERA_ERROR_DEFINE(err, msg)
Definition and initialisation of an error constant.
Definition error.h:71
#define LERR_(_NAME_)
Definition error.hpp:45
Definition of time code formats This header is part of the Lumiera time and timecode handling library...
unsigned int uint
Definition integral.hpp:29
void wrapFrames(SmpteTC *thisTC, int rawFrames)
Definition timecode.cpp:245
void wrapMinutes(SmpteTC *thisTC, int rawMins)
Definition timecode.cpp:261
void wrapSeconds(SmpteTC *thisTC, int rawSecs)
Definition timecode.cpp:253
void setupComponentNormalisation(SmpteTC &thisTC)
bind the individual Digxel mutation functors to normalise raw component values
Definition timecode.cpp:282
void wrapHours(SmpteTC *thisTC, int rawHours)
Definition timecode.cpp:269
int64_t FrameCnt
relative framecount or frame number.
Definition digxel.hpp:310
Quantiser const & QuantR
Definition formats.hpp:57
boost::rational< int64_t > FSecs
rational representation of fractional seconds
Implementation namespace for support and library code.
LumieraError< LERR_(INVALID)> Invalid
Definition error.hpp:211
Lumiera public interface.
Definition advice.hpp:102
bool isSameObject(A const &a, B const &b)
compare plain object identity, based directly on the referee's memory identities.
Definition util.hpp:421
IDiv< I > floorwrap(I num, I den)
scale wrapping operation.
OBJ * unConst(const OBJ *)
shortcut to save some typing when having to define const and non-const variants of member functions
Definition util.hpp:358
static void rebuild(FrameNr &, QuantR, TimeValue const &)
build up a frame count by quantising the given time value
Definition timecode.cpp:150
static TimeValue evaluate(FrameNr const &, QuantR)
calculate the time point denoted by this frame count
Definition timecode.cpp:157
static TimeValue parse(string const &, QuantR)
try to parse a frame number specification
Definition timecode.cpp:64
static TimeValue parse(string const &, QuantR)
Definition timecode.cpp:84
static TimeValue parse(string const &, QuantR)
try to parse a time specification in seconds or fractional seconds.
Definition timecode.cpp:112
Widely used standard media timecode format.
Definition formats.hpp:92
static TimeValue evaluate(SmpteTC const &, QuantR)
calculate the time point denoted by this SMPTE timecode, by summing up the timecode's components
Definition timecode.cpp:178
static void applyRangeLimitStrategy(SmpteTC &)
handle the limits of SMPTE timecode range.
Definition timecode.cpp:232
static uint getFramerate(QuantR, TimeValue const &)
yield the Framerate in effect at that point.
Definition timecode.cpp:202
static void rebuild(SmpteTC &, QuantR, TimeValue const &)
build up a SMPTE timecode by quantising the given time value and then splitting it into hours,...
Definition timecode.cpp:168
static TimeValue parse(string const &, QuantR)
Definition timecode.cpp:77
helper to treat int or long division uniformly
#define SUB_EXPR(N)
Timecode handling library This header defines the foundation interface TCode to represent a grid alig...
Support library to represent grid-aligned time specifications This is part of Lumiera's time and time...
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...